#include "client.h"
#define BIG_FILE 1024*1024*100

//封装2个小火车函数，用于收发，在本 .c文件中，减少很多代码量
static void send_train(int netfd, char buf[], int len){
    train_t train;
    memset(&train, 0, sizeof(train));
    train.length = len;
    memcpy(train.data, buf, train.length);
    printf("发送长度 train.length = %d\n", train.length);
    ssize_t send_sret = send(netfd, &train, sizeof(int)+train.length, MSG_NOSIGNAL);
}
static void recv_train(int netfd){
    train_t train;
    memset(&train, 0, sizeof(train));
    recv(netfd, &train.length, sizeof(int), MSG_WAITALL);
    printf("接收长度 train.length = %d\n", train.length);
    ssize_t recv_sret = recv(netfd, train.data, train.length, MSG_WAITALL);
}

//客户端 puts 上传文件到服务端
int sendFile(int sockfd, cmdInfo_t *cmdInfo){
    //第 001 步，判断是不是大文件，直接正常发
    //设计标志位 falg
    int flag = 0;
    //打开文件，准备捉妖！
    int fd = open(cmdInfo->arg, O_RDWR);
    printf("cmdInfo->arg = %s\n", cmdInfo->arg);
    printf("fd = %d\n", fd);
    printf("cmfInfo->fileSize = %ld\n", cmdInfo->fileSize);
    //已经发送文件大小
    off_t total_size = 0;
    
    //char buf1234[] = "ojbk";
    //send_train(sockfd, buf1234, sizeof(buf1234));
        
    while(total_size < cmdInfo->fileSize){
        printf("进入正常发分支！\n");
        train_t train;
        memset(&train, 0, sizeof(train));
        ssize_t sret = read(fd, train.data, sizeof(train.data));
        train.length = sret;
        if(sret == 0){
            break;
        }
        printf("train.length = %ld 个字节\n", sret);
        
        send(sockfd, &train, sizeof(int)+train.length, MSG_NOSIGNAL);
        printf("发送成功！\n");
        
        //关键先生到位,每次接收一下标识位置
        recv(sockfd, &train.length, sizeof(int), MSG_WAITALL);
        sret = recv(sockfd, train.data, train.length, MSG_WAITALL);
        
        if(sret == 0){
            break;
        }
        if(strcmp(train.data, "0") == 0){
            //表示触发断点重传了，重新发这个小火车
            //在重发之前，直接发送现成的 flag = 0 给服务端
            char buf[] = "0";
            send_train(sockfd, buf, sizeof(buf));
            continue;
        }else if(sret == -1){
            char buf001[] = "0";
            send_train(sockfd, buf001, sizeof(buf001));
            continue;
        }
        total_size += 1000;
    }
    printf("关闭上传 fd ！\n");
    char buf321[] = {0};
    send_train(sockfd, buf321, sizeof(buf321));
    close(fd);
    return 0;
}

//客户端 gets 下载文件到服务端
int recvFile(int sockfd, cmdInfo_t *cmdInfo){
    //先接收服务端信息，为 -1 表示下载失败
    train_t train;
    memset(&train, 0, sizeof(train));
    recv(sockfd, &train.length, sizeof(int), MSG_WAITALL);
    recv(sockfd, train.data, train.length, MSG_WAITALL);
    if(strcmp(train.data, "-1") == 0){
        printf("文件下载失败，服务端，没有该文件！\n");
        return -1;
    }
    //下载的文件应该存放到哪里呢？
    char str[100] = {0};
    if(getcwd(str, sizeof(str)) != NULL){
        printf("当前工作目录: %s\n", str);
    }else{
        printf("下载失败！\n");
        return -1;
    }
    strcat(str, cmdInfo->fileName);
    int fd = open(str, O_RDWR|O_CREAT, 0666);
    if(fd == -1){
        printf("下载失败！\n");
        return -1;
    }

    //没毛病，就继续往下走，正式开始接收
    off_t total_size = 0;//维护一个变量，表示已经接收了多少数据量
    int flag = 1;//维护一个标识位，用于断点续传

    while(total_size < cmdInfo->fileSize){
        train_t train;
        memset(&train, 0, sizeof(train));
        recv(sockfd, &train.length, sizeof(int), MSG_WAITALL);
        if(train.length == 0){
            break;//经典最后一个数据包是空包
        }
        ssize_t sret = recv(sockfd, train.data, train.length, MSG_WAITALL);
        printf("客户端收到 %ld 个字节！\n", sret);

        //然后，关键先生 sret 来了
        if(sret == -1){
            //表示此次接收数据出现问题，小火车不对劲！
            char buf001[] = "0";
            send_train(sockfd, buf001, sizeof(buf001));
            continue;//重新接收
        }
        //走到这里，表示接收数据包没问题，需要发送一个成功接收的信息给客户端
        //这里要么走这里，要么走上面，都要给服务端先回一个状态信息
        char buf002[] = "ojbk!";
        send_train(sockfd, buf002, sizeof(buf002));
        //然后是正式写入，写入提前准备好的工作目录
        sret = write(fd, train.data, sizeof(train.data));
        printf("写入 %ld 个字节！\n", sret);
        total_size += 1000;
    }
    close(fd);
    return -1;
}
